%{
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>

#include "epub.h"
#include "liblista.h"

#define AUXSIZE 10000000 /* size in bits for aux_txt */


/************************* auxiliary functions for print nodes ****************/
void show_str_node(void *d){
	char *a = (char *) d;
	printf("\t%s\n",a);
}
void show_chapter_node(void *d){
	chapter *a = (chapter *) d;

	printf("NODO:\n");
	printf("\tTITULO: %s\n", a->title);
	printf("\tPARRAFOS: \n");

	mostrar_lista(&(a->content), show_str_node);	
}
/******************************************************************************/


/* GLOBAL VARS */
char *aux_txt;// text container
chapter *aux_chapter;//chapter auxiliar container
lista epub = NULL; //chapter(type) list
lista l_img = NULL; //images name list(string list)
lista l_error = NULL; //errors ocurred while pasing code (string list)


/*
	Adds title for aux_chapter container
*/
void add_title(char *str)
{	
	aux_chapter->title = str;
}

/*
	Adds text to text container aux_txt
*/
void add_txt(char *txt)
{	
	//printf("ANADIDO ARRIBA: %s\n", txt);fflush(stdout);
	strcat(aux_txt, txt);
	//when txt is used free it.
	//free(txt);
}

/*
	Adds subtitle to text container aux_txt
*/
void add_sub_txt(char *txt)
{
	strcat(aux_txt, "<h2>");	
	add_txt(txt);
	strcat(aux_txt, "</h2>");	
}

/*
	Adds subsubtitle to text container aux_txt
*/
void add_ssub_txt(char *txt)
{
	strcat(aux_txt, "<h3>");	
	add_txt(txt);
	strcat(aux_txt, "</h3>");	
}


/*
 *Change spaces
 */
void underline(char *word)
{
	int i, len;
	
	len = strlen(word);

	for(i=0; i<len; i++)
		if (word[i] == ' ')
			word[i] = '_';
}

/*
	Adds img in img format to chapterlist
*/
void add_img(char *txt)
{
	//change space " " for underline "_" its necessary for find image in wikipedia
	underline(txt);
	//add image to name image list(after we'll use this list for download all images)
	insertar_nodo(&l_img, strdup(txt));	

	strcat(aux_txt, "<img class=\"imagencentrada\" src=\"../Images/");
	add_txt(txt);
	strcat(aux_txt, "\" />");
}

/*
	Adds new paragraph.
	New content(string) in auxiliary chapter node.
*/
void add_paragraph()
{
	int parag_len;

	parag_len = strlen(aux_txt);
	if(parag_len){
		insertar_nodo(&(aux_chapter->content), strdup(aux_txt));
		//printf("ANADIDOS:  %s\n", aux_txt);
		//restore container
		aux_txt[0] = '\0';
		
	}
}

/*
	Adds new chapter(store in auxiliary chapter node)
	into chapter list (epub GLOBAL VAR)
*/
void add_chapter()
{
	insertar_nodo(&epub, aux_chapter);

	//clean auxiliary chapter
	aux_chapter = (chapter *) malloc(sizeof(chapter));
	crear_lista(&(aux_chapter->content));
}

char *concat_word(char *a, char *b)
{
	char *result = (char *)malloc(sizeof(char)*(strlen(a)+strlen(b)+1));
	
	strcpy(result,a);
	strcat(result,b);

	return result;

}

void add_error(char *msg)
{
	char *aux;

	aux =(char *)malloc(sizeof(char)*(strlen(msg) + strlen(aux_txt)+50));
	strcpy(aux, msg);
	strcat(aux, "\n\terror after : \n");
	strcat(aux, aux_txt);
	strcat(aux, "\n");
	if (insertar_nodo(&l_error, aux)== -1) 
		perror("No se puede insertar nodo error.");

}

int yyerror(char *err)
{
	//ERRORS submitted to add_error when finding in parser
}


void cerrar_error()
{
    mostrar_lista(&l_error, show_str_node);
    exit(0);
}

/******************************************************************************/

%}
%union{
	char  *valChar;	
	int   valInt;
	float valFloat;
}

%token JUMP
%token VBAR
%token SHARP
%token ITAL
%token BOLD
%token ITBOLD
%token TIT
%token STIT
%token SSTIT
%token ILINK
%token FLINK
%token IFILE
%token ILABEL
%token FLABEL
%token ITARGET
%token FTARGET
%token IREF
%token FREF
%token <valChar> WORD


%type <valChar>  decored_text final_link decored_text_link single_text text_in in_decored_text in_decored_text_link

%start S
%%
S : chapters{}
      ;
chapters : parts chapters {}
			| parts{}
		;

parts : title content{add_chapter();}
	//	|error content {add_error("ERROR: No se encuentra el titulo."); cerrar_error();}
		;

title : TIT single_text TIT {add_title($2);}
		|TIT error TIT {add_error("ERROR: Titulo con formato no valido");}
		//Title could be Bold or Link but It will be incorrect in wiki standard style.
		;

content : text content{}
			|links content{}
			|jump content{}
			|text{}
			|links {}
			|jump {}
			;

jump: JUMP {add_paragraph();};


text: decored_text {add_txt($1);}
	|STIT single_text STIT {add_sub_txt($2);}
	|SSTIT single_text SSTIT {add_ssub_txt($2);}
	|STIT error STIT {add_error("ERROR: Subtitulo con formato no valido");}
	|SSTIT error SSTIT {add_error("ERROR: Subtitulo con formato no valido");}
	|target {}
	|ref {}
	|WORD {add_txt($1);}
	|FREF {}
	;


single_text: WORD  {$$ = $1;}
			|WORD single_text{$$ = concat_word($1, $2);}
			;

target : ITARGET in_target FTARGET {}
		|ITARGET error FTARGET {add_error("ERROR: Target mal formado");}
		;

ref : IREF in_ref FREF {}
	| IREF error FREF {add_error("ERROR: Ref mal formado");}
	;


in_ref : in_target_text in_ref {}
			|in_target_text {}
			|JUMP in_ref {}
			|JUMP {}
			;

in_target : in_target_text in_target{}
			|in_target_text {}
			|JUMP in_target {}
			|JUMP {}
			|FREF in_target {}
			|FREF {}
			;


in_target_text:	 WORD {}
				| final_link{}
				| SHARP {}
				| VBAR {}
				| target {}
				| img {}
				| BOLD in_decored_text BOLD {}
				| ITAL in_decored_text ITAL {}
				| ITBOLD in_decored_text ITBOLD {}
				| BOLD in_decored_text error {add_error("ERROR: Etiqueta negrita no cerrada");}
				| ITAL in_decored_text error {add_error("ERROR: Etiqueta italica no cerrada");}
				| ITBOLD in_decored_text error {add_error("ERROR: Etiqueta negrita-italica no cerrada");}
				| ref {}
				;

in_decored_text: WORD in_decored_text{$$ = concat_word($1, $2);}
		| final_link in_decored_text {$$ = concat_word($1,$2);}
		| WORD {$$ = $1;}
		| final_link{$$ = $1;}
		| SHARP in_decored_text {$$ = concat_word(" # ",$2);}
		| VBAR in_decored_text {$$ = concat_word(" | ",$2);}
		| SHARP {$$ = " # ";}
		| VBAR {$$ = " | ";}
		| target  in_decored_text { $$ = concat_word(" ",$2);}
		| target { $$ = " ";}
		| ref in_decored_text {$$ = concat_word(" ",$2);}
		| ref {$$ = " ";}
		;

decored_text: BOLD in_decored_text BOLD {$$ = $2;}
			|ITAL in_decored_text ITAL {$$ = $2;}
			|ITBOLD in_decored_text ITBOLD {$$ = $2;}
			|BOLD error BOLD {add_error("ERROR: Formato invalido dentro de una negrita"); $$ = "#ERROR";}
			|ITAL error ITAL {add_error("ERROR: Formato invalido dentro de una italica"); $$ = "#ERROR";}
			|ITBOLD error ITBOLD {add_error("ERROR: Formato invalido dentro de una negrita-italica"); $$ = "#ERROR";}
			|BOLD in_decored_text error {add_error("ERROR: Etiquetas negrita invalidas");$$ = $2;}
			|ITAL in_decored_text error {add_error("ERROR: Etiquetas italica invalidas");$$ = $2;}
			|ITBOLD in_decored_text error {add_error("ERROR: Etiquetas negrita-italica invalidas");$$ = $2;}
			|SHARP {$$ = " # ";}
			|VBAR {$$ = " | ";}
			;

in_decored_text_link: WORD in_decored_text_link{$$ = concat_word($1, $2);}
		| final_link in_decored_text_link {$$ = concat_word($1,$2);}
		| WORD {$$ = $1;}
		| final_link{$$ = $1;}
		| target  in_decored_text_link { $$ = concat_word(" ",$2);}
		| target { $$ = " ";}
		| ref in_decored_text_link {$$ = concat_word(" ",$2);}
		| ref {$$ = " ";}
		| FREF in_decored_text_link {}
		| FREF {}
		;

decored_text_link:BOLD in_decored_text_link BOLD {$$ = $2;}
				|ITAL in_decored_text_link ITAL {$$ = $2;}
				|ITBOLD in_decored_text_link ITBOLD {$$ = $2;}
				;

links : final_link {add_txt($1);}
		|img {}
		;
img: IFILE WORD fileopt FLINK {add_img($2);}
	|IFILE error fileopt FLINK {add_error("ERROR: Formato de imagenes incorrecto"); add_txt("#image_ERROR");}

text_in : WORD text_in {$$ = $1;}
		| WORD {$$ = $1;}
		| decored_text_link text_in{$$ = $1;}
		| decored_text_link {$$ = $1;}
		;

final_link : ILINK text_in FLINK {$$ = $2;}
		| ILINK text_in VBAR text_in FLINK {$$ = $4;}	  
		| ILINK text_in VBAR FLINK {$$ = $2;}/*Parsear parentesis en C (Opcional)*/
		| ILINK SHARP text_in VBAR text_in FLINK {$$ = $5;}
		| ILINK text_in SHARP text_in VBAR text_in FLINK {$$ = $6;}
		| ILINK error FLINK {add_error("ERROR: Formato de link incorrecto"); $$ = "#ERROR";}
		;

fileopt : VBAR fileopt_cont {/* image options (ignored) */}
		| VBAR fileopt_cont fileopt {}
		;

fileopt_cont :	final_link {}
			|	final_link fileopt_cont {}
			|	decored_text_link {}
			|	decored_text_link fileopt_cont {}
			| 	WORD fileopt_cont {}
			|	WORD {}
			|	target fileopt_cont {}
			|	target {}
			|	JUMP fileopt_cont {}
			|	JUMP {}
			|	ref fileopt_cont {}
			|	ref {}
			|	FREF fileopt_cont {}
			|	FREF {}
			;


%%
/*****************************************************************************/
/*
	Init 
	Inicializa variables antes de la ejecucion del parser
*/
void init()
{
 	aux_txt = (char *) malloc(sizeof(char) * AUXSIZE);
	aux_chapter = (chapter *) malloc(sizeof(chapter));
	crear_lista(&(aux_chapter->content));
}


int main(int argc, char *argv[]) {

	init();
	printf("\n\n\nParser: "); fflush(stdout);
	yyparse();
	printf("[COMPLETED]\n\n");fflush(stdout);
	
	//mostrar_lista(&epub, show_chapter_node);
	printf("ERRORS:\n");
	printf("\t--------------------------------------------------------------------\n");

	mostrar_lista(&l_error, show_str_node);
	printf("\n\t--------------------------------------------------------------------\n\n");

	if(create_epub(epub, l_img, argv[1]) == -1)
		printf("ERROR: impossible make epub.\n");
	
	return 0;
}
